package com.zijidelu.luframework.base.dict;


import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 通用字典接口，支持 key/value 快速查询。
 * <p>
 * 特点：
 * - 无需外部注册
 * - 自动构建缓存
 * - 枚举线程安全
 * - 支持 getByKey / getByValue
 *
 * @author ZIJIDELU
 * @datetime 2024/9/27 00:33
 */
public interface Dict<K, V> {

    /**
     * 获取枚举的 key。
     */
    K getKey();

    /**
     * 获取枚举的 value。
     */
    V getValue();

    /* -------------------------------------------------------- */

    /**
     * 根据 key 获取对应的枚举。
     */
    static <K, V, T extends Enum<T> & Dict<K, V>> T getByKey(Class<T> clazz, K key) {
        @SuppressWarnings("unchecked")
        T result = (T) Cache.of(clazz).byKey.get(key);
        return result;
    }

    /**
     * 根据 value 获取对应的枚举。
     */
    static <K, V, T extends Enum<T> & Dict<K, V>> T getByValue(Class<T> clazz, V value) {
        @SuppressWarnings("unchecked")
        T result = (T) Cache.of(clazz).byValue.get(value);
        return result;
    }

    /**
     * 获取 key→value 映射表。
     */
    static <K, V, T extends Enum<T> & Dict<K, V>> Map<K, V> toMap(Class<T> clazz) {
        @SuppressWarnings("unchecked")
        Map<K, V> map = (Map<K, V>) Cache.of(clazz).keyToValue;
        return map;
    }

    /**
     * 内部缓存实现（通用、线程安全、按枚举类型惰性构建）。
     */
    class Cache {
        // Cache map keyed by enum class
        private static final Map<Class<?>, Cache> CACHE_MAP = new ConcurrentHashMap<>();

        // 使用通用类型存储，返回处再做受检转换
        final Map<Object, Enum<?>> byKey;
        final Map<Object, Enum<?>> byValue;
        final Map<Object, Object> keyToValue;

        // 返回带有受检转换的缓存实例
        @SuppressWarnings("unchecked")
        static <T extends Enum<T> & Dict<?, ?>> Cache of(Class<T> clazz) {
            return CACHE_MAP.computeIfAbsent(clazz, c -> new Cache(clazz));
        }

        private <T extends Enum<T> & Dict<?, ?>> Cache(Class<T> clazz) {
            T[] constants = clazz.getEnumConstants();
            // 构建索引：key -> enum
            this.byKey = Arrays.stream(constants)
                    .collect(Collectors.toUnmodifiableMap(Dict::getKey, e -> e, (a, b) -> a));
            // 构建索引：value -> enum
            this.byValue = Arrays.stream(constants)
                    .collect(Collectors.toUnmodifiableMap(Dict::getValue, e -> e, (a, b) -> a));
            // key -> value map
            this.keyToValue = Arrays.stream(constants)
                    .collect(Collectors.toUnmodifiableMap(Dict::getKey, Dict::getValue, (a, b) -> a));
        }
    }
}
